package crons

import (
	"context"
	"github.com/spf13/viper"
	"go.didapinche.com/foundation/plat-echo/app/ops/models"
	"go.didapinche.com/foundation/plat-echo/app/ops/repositories"
	promentheus "go.didapinche.com/foundation/plat-echo/pkg/prometheus"
	"go.uber.org/zap"
	"strconv"
)

type AlertReloadJob struct {
	logger            *zap.Logger
	prometheus        *promentheus.PrometheusService
	apiRepository     repositories.ApiRepository
	appRepository     repositories.ApplicationRepository
	currentRepository repositories.AlertCurrentRepository
	graphRepository   repositories.GraphRepository
}

func NewAlertReloadJob(logger *zap.Logger,
	currentRepository repositories.AlertCurrentRepository,
	graphRepository repositories.GraphRepository,
	apiRepository repositories.ApiRepository,
	appRepository repositories.ApplicationRepository,
	prometheus *promentheus.PrometheusService) *AlertReloadJob {
	return &AlertReloadJob{
		logger:            logger,
		apiRepository:     apiRepository,
		appRepository:     appRepository,
		currentRepository: currentRepository,
		graphRepository:   graphRepository,
		prometheus:        prometheus,
	}
}

func (a *AlertReloadJob) Run() {
	a.logger.Info("alerts reload job start")
	err := a.prometheus.Reload()
	if err != nil {
		a.logger.Error("alert_reload_job run error", zap.Error(err))
	}
	a.logger.Info("alerts reload job end")
	if !viper.GetBool("alert.reload") {
		return
	}
	alerts, err := a.prometheus.GetAlerts()
	if alerts == nil {
		return
	}
	m := make(map[uint64]int)
	ctx := context.Background()
	for _, info := range alerts.Data.AlertInfos {
		if info.Labels["kind"] == "0" {
			graphID, err := strconv.ParseUint(string(info.Labels["graph_id"]), 10, 64)
			if err == nil {
				current, err := a.currentRepository.FirstByGraphID(ctx, graphID)
				if err == nil {
					m[current.ID] = 0
				}
			}
		} else if info.Labels["kind"] == "1" {
			templateID, err := strconv.ParseUint(string(info.Labels["template_id"]), 10, 64)
			if err != nil {
				a.logger.Error("templateID don't int type", zap.Error(err))
				continue
			}
			api := new(models.Api)
			if _, ok := info.Labels["uri"]; ok {
				uri := string(info.Labels["uri"])
				method := string(info.Labels["method"])
				app := string(info.Labels["app"])
				api, err = a.apiRepository.FindByHttpPath(ctx, app, method, uri)
				if err != nil {
					a.logger.Error("call apiRepository FindByID", zap.Error(err))
					continue
				}
			} else {
				service := string(info.Labels["service"])
				method := string(info.Labels["method"])
				app := string(info.Labels["app"])
				api, err = a.apiRepository.FindByZeus(ctx, app, service, method, 3)
				if err != nil {
					a.logger.Error("call apiRepository FindByID", zap.Error(err))
					continue
				}
			}

			graph, err := a.graphRepository.FindGraphByApiIDAndTemplateID(ctx, api.ID, templateID)
			if err != nil {
				a.logger.Error("call graphRepository FindGraphByApiIDAndTemplateID", zap.Error(err))
				continue
			}

			current, err := a.currentRepository.FirstByGraphID(ctx, graph.ID)
			if err == nil {
				m[current.ID] = 0
			}
		}
	}
	alerts2, err := a.currentRepository.FindAll(ctx)
	if err != nil {
		return
	}
	for _, alert := range alerts2 {
		if _, ok := m[alert.ID]; !ok {
			a.currentRepository.Delete(ctx, alert.GraphID)
		}
	}
}

func (a *AlertReloadJob) Cron() string {
	return "0 0/1 * * * ?"
}

func (a *AlertReloadJob) Name() string {
	return "alert_reload_job"
}
